package cn.lili.modules.promotion.serviceimpl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.PromotionTypeEnum;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.exchange.AmqpExchangeProperties;
import cn.lili.modules.goods.client.GoodsClient;
import cn.lili.modules.goods.entity.dos.Goods;
import cn.lili.modules.goods.entity.dos.GoodsSku;
import cn.lili.modules.goods.entity.dto.GoodsSearchParams;
import cn.lili.modules.member.client.UserClient;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.order.order.client.OrderClient;
import cn.lili.modules.order.order.entity.dos.Order;
import cn.lili.modules.order.order.entity.enums.OrderStatusEnum;
import cn.lili.modules.order.order.entity.enums.PayStatusEnum;
import cn.lili.modules.promotion.entity.dos.Pintuan;
import cn.lili.modules.promotion.entity.dos.PromotionGoods;
import cn.lili.modules.promotion.entity.dos.SeckillApply;
import cn.lili.modules.promotion.entity.dto.search.PintuanSearchParams;
import cn.lili.modules.promotion.entity.dto.search.PromotionGoodsSearchParams;
import cn.lili.modules.promotion.entity.enums.PromotionsScopeTypeEnum;
import cn.lili.modules.promotion.entity.enums.PromotionsStatusEnum;
import cn.lili.modules.promotion.entity.vos.PintuanMemberVO;
import cn.lili.modules.promotion.entity.vos.PintuanShareVO;
import cn.lili.modules.promotion.entity.vos.PintuanVO;
import cn.lili.modules.promotion.entity.vos.SeckillGoodsVO;
import cn.lili.modules.promotion.mapper.PintuanMapper;
import cn.lili.modules.promotion.service.PintuanService;
import cn.lili.modules.promotion.service.PromotionGoodsService;
import cn.lili.modules.promotion.tools.PromotionTools;
import cn.lili.routing.GoodsRoutingKey;
import cn.lili.routing.PromotionRoutingKey;
import cn.lili.trigger.enums.DelayTypeEnums;
import cn.lili.trigger.interfaces.TimeTrigger;
import cn.lili.trigger.model.TimeTriggerMsg;
import cn.lili.trigger.util.DelayQueueTools;
import cn.lili.util.AmqpMessage;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.transaction.annotation.ShardingTransactionType;
import org.apache.shardingsphere.transaction.core.TransactionType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 拼团业务层实现
 *
 * @author Chopper
 * @since 2020/8/21
 */
@Service
@RequiredArgsConstructor
public class PintuanServiceImpl extends AbstractPromotionsServiceImpl<PintuanMapper, Pintuan> implements PintuanService {

    /**
     * 促销商品
     */
    private final PromotionGoodsService promotionGoodsService;
    /**
     * 规格商品
     */
    private final GoodsClient goodsClient;
    /**
     * 会员
     */
    private final UserClient userClient;
    /**
     * 订单
     */
    private final OrderClient orderClient;


    private final AmqpExchangeProperties amqpExchangeProperties;

    /**
     * 延时任务
     */
    private final TimeTrigger timeTrigger;

    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;


    /**
     * 获取当前拼团的会员
     *
     * @param pintuanId 拼图id
     * @return 当前拼团的会员列表
     */
    @Override
    public List<PintuanMemberVO> getPintuanMember(String pintuanId, String skuId) {
        List<PintuanMemberVO> members = new ArrayList<>();
        Pintuan pintuan = this.getById(pintuanId);
        if (pintuan == null) {
            log.error("拼团活动为" + pintuanId + "的拼团活动不存在！");
            return new ArrayList<>();
        }
        List<Order> orders = orderClient.queryListByPromotionId(PromotionTypeEnum.PINTUAN.name(), PayStatusEnum.PAID.name(), "", pintuanId, skuId);
        //遍历订单状态为已支付，为团长的拼团订单
        for (Order order : orders) {
            User member = userClient.getById(order.getBuyerId());
            PintuanMemberVO memberVO = new PintuanMemberVO(member);
            //获取已参团人数
            this.setMemberByParentOrderVONum(memberVO, pintuan.getRequiredNum(), order.getSn());
            memberVO.setOrderSn(order.getSn());
            members.add(memberVO);
        }
        return members;
    }

    /**
     * 查询拼团活动详情
     *
     * @param id 拼团ID
     * @return 拼团活动详情
     */
    @Override
    public PintuanVO getPintuanVO(String id) {
        Pintuan pintuan = this.getById(id);
        if (pintuan == null) {
            log.error("拼团活动id[" + id + "]的拼团活动不存在！");
            throw new ServiceException(ResultCode.PINTUAN_NOT_EXIST_ERROR);
        }
        PintuanVO pintuanVO = new PintuanVO(pintuan);
        PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
        searchParams.setPromotionId(pintuan.getId());
        pintuanVO.setPromotionGoodsList(promotionGoodsService.listFindAllByPinTuan(searchParams));
        return pintuanVO;
    }

    /**
     * 查询拼团活动详情
     *
     * @param searchParams 拼团查询参数
     * @return 拼团活动详情
     */
    @Override
    public PintuanVO getPintuanVO(PintuanSearchParams searchParams) {
        Pintuan pintuan = this.getOne(searchParams.queryWrapper(), false);
        if (pintuan == null) {
            log.error("拼团活动不存在！{" + searchParams + "}");
            throw new ServiceException(ResultCode.PINTUAN_NOT_EXIST_ERROR);
        }
        PintuanVO pintuanVO = new PintuanVO(pintuan);
        PromotionGoodsSearchParams promotionGoodsSearchParams = new PromotionGoodsSearchParams();
        promotionGoodsSearchParams.setPromotionId(pintuan.getId());
        pintuanVO.setPromotionGoodsList(promotionGoodsService.listFindAll(promotionGoodsSearchParams));
        return pintuanVO;
    }

    /**
     * 获取拼团分享信息
     *
     * @param parentOrderSn 拼团团长订单sn
     * @param skuId         商品skuId
     * @return 拼团分享信息
     */
    @Override
    public PintuanShareVO getPintuanShareInfo(String parentOrderSn, String skuId) {
        PintuanShareVO pintuanShareVO = new PintuanShareVO();
        pintuanShareVO.setPintuanMemberVOS(new ArrayList<>());
        //查找团长订单和已和当前拼团订单拼团的订单
        List<Order> orders = orderClient.queryListByPromotion(PromotionTypeEnum.PINTUAN.name(), PayStatusEnum.PAID.name(), parentOrderSn, parentOrderSn);
        this.setPintuanOrderInfo(orders, pintuanShareVO, skuId);
        //如果为根据团员订单sn查询拼团订单信息时，找到团长订单sn，然后找到所有参与到同一拼团的订单信息
        if (!orders.isEmpty() && pintuanShareVO.getPromotionGoods() == null) {
            List<Order> parentOrders = orderClient.queryListByPromotion(PromotionTypeEnum.PINTUAN.name(), PayStatusEnum.PAID.name(), orders.get(0).getParentOrderSn(), orders.get(0).getParentOrderSn());
            this.setPintuanOrderInfo(parentOrders, pintuanShareVO, skuId);
        }
        return pintuanShareVO;
    }

    /**
     * 更新促销商品信息
     *
     * @param promotions 促销实体
     * @return 是否更新成功
     */
    @Override
    @Transactional
    @ShardingTransactionType(TransactionType.BASE)
    public boolean updatePromotionsGoods(Pintuan promotions) {
        boolean result = super.updatePromotionsGoods(promotions);
        if (!PromotionsStatusEnum.CLOSE.name().equals(promotions.getPromotionStatus()) && PromotionsScopeTypeEnum.PORTION_GOODS.name().equals(promotions.getScopeType()) && promotions instanceof PintuanVO pintuanVO) {
            this.updatePintuanPromotionGoods(pintuanVO);

            //发送促销活动开始的延时任务
            this.timeTrigger.addDelay(TimeTriggerMsg.builder().exchange(amqpExchangeProperties.getPromotion()).triggerTime(promotions.getEndTime().getTime()).param(promotions).uniqueKey(DelayQueueTools.wrapperUniqueKey(DelayTypeEnums.PINTUAN_ORDER, (promotions.getId()))).routingKey(PromotionRoutingKey.PINTUAN).build());
        }
        if (promotions.getEndTime() == null && promotions.getStartTime() == null) {
            //过滤父级拼团订单，根据父级拼团订单分组
            this.orderClient.checkFictitiousOrder(promotions.getId(), promotions.getRequiredNum(), promotions.getFictitious());
        }
        return result;
    }

    /**
     * 更新促销信息到商品索引
     *
     * @param promotions 促销实体
     */
    @Override
    public void updateEsGoodsIndex(Pintuan promotions) {
        Pintuan pintuan = JSONUtil.parse(promotions).toBean(Pintuan.class);
        super.updateEsGoodsIndex(pintuan);
    }

    /**
     * 当前促销类型
     *
     * @return 当前促销类型
     */
    @Override
    public PromotionTypeEnum getPromotionType() {
        return PromotionTypeEnum.PINTUAN;
    }

    /**
     * 根据订单信息，从中提取出拼团信息，设置拼团信息
     *
     * @param orders         订单列表
     * @param pintuanShareVO 拼团信息
     * @param skuId          商品skuId（用于获取拼团商品信息）
     */
    private void setPintuanOrderInfo(List<Order> orders, PintuanShareVO pintuanShareVO, String skuId) {
        for (Order order : orders) {
            if (pintuanShareVO.getPintuanMemberVOS().stream().anyMatch(i -> i.getMemberId().equals(order.getBuyerId()))) {
                continue;
            }
            User member = userClient.getById(order.getBuyerId());
            PintuanMemberVO memberVO = new PintuanMemberVO(member);
            if (CharSequenceUtil.isEmpty(order.getParentOrderSn())) {
                memberVO.setOrderSn("");
                PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
                searchParams.setPromotionId(order.getPromotionId());
                searchParams.setSkuId(skuId);
                PromotionGoods promotionGoods = promotionGoodsService.getPromotionsGoods(searchParams);
                if (promotionGoods == null) {
                    throw new ServiceException(ResultCode.PINTUAN_GOODS_NOT_EXIST_ERROR);
                }
                pintuanShareVO.setPromotionGoods(promotionGoods);
                Pintuan pintuanById = this.getById(order.getPromotionId());
                //获取已参团人数
                this.setMemberVONum(memberVO, pintuanById.getRequiredNum(), order.getSn());
                if (OrderStatusEnum.COMPLETED.name().equals(order.getOrderStatus()) && Boolean.TRUE.equals(pintuanById.getFictitious())) {
                    memberVO.setGroupedNum(pintuanById.getRequiredNum());
                    memberVO.setToBeGroupedNum(0L);
                }
            }
            pintuanShareVO.getPintuanMemberVOS().add(memberVO);
        }
    }

    private void setMemberByParentOrderVONum(PintuanMemberVO memberVO, Integer requiredNum, String orderSn) {
        List<Order> orders = this.orderClient.getByParentSn(orderSn);

        log.debug("拼团订单 " + JSONObject.toJSONString(orders));

        orders = orders.stream().filter(e -> {
            switch (OrderStatusEnum.valueOf(e.getOrderStatus())) {
                case PAID, COMPLETED, PLATFORM_PAID, DELIVERED, STAY_PICKED_UP, TAKE, UNDELIVERED -> {
                    return true;
                }
            }
            return false;
        }).toList();

        log.debug("拼团订单 " + JSONObject.toJSONString(orders));

        //获取待参团人数
        long toBoGrouped = requiredNum - orders.size() - 1;
        memberVO.setGroupNum(requiredNum);
        memberVO.setGroupedNum(orders.size() + 1);
        memberVO.setToBeGroupedNum(toBoGrouped);
    }

    private void setMemberVONum(PintuanMemberVO memberVO, Integer requiredNum, String orderSn) {
        long count = this.orderClient.queryCountByPromotion(PromotionTypeEnum.PINTUAN.name(), PayStatusEnum.PAID.name(), orderSn, orderSn);
        //获取待参团人数
        long toBoGrouped = requiredNum - count;
        memberVO.setGroupNum(requiredNum);
        memberVO.setGroupedNum(count);
        memberVO.setToBeGroupedNum(toBoGrouped);
    }

    /**
     * 更新记录的促销商品信息
     *
     * @param pintuan 拼团信息
     */
    private void updatePintuanPromotionGoods(PintuanVO pintuan) {

        if (pintuan.getPromotionGoodsList() != null && !pintuan.getPromotionGoodsList().isEmpty()) {
            List<PromotionGoods> promotionGoods = PromotionTools.promotionGoodsInit(pintuan.getPromotionGoodsList(), pintuan, PromotionTypeEnum.PINTUAN);
            for (PromotionGoods promotionGood : promotionGoods) {
                GoodsSku sku = goodsClient.getGoodsSkuById(promotionGood.getSkuId());
                /*if(sku.getGreenScore() != 0) {
                    throw new ServiceException("拼团商品绿色积分必须为0");
                }*/
                promotionGood.setId(null);
                if (goodsClient.getCanPromotionGoodsSkuByIdFromCache(promotionGood.getSkuId()) == null) {
                    log.error("商品[" + promotionGood.getGoodsName() + "]不存在或处于不可售卖状态！");
                    throw new ServiceException("商品[" + promotionGood.getGoodsName() + "]不存在或处于不可售卖状态！");
                }
                //查询是否在同一时间段参与了拼团活动
                Integer count = promotionGoodsService.findInnerOverlapPromotionGoods(PromotionTypeEnum.SECKILL.name(), promotionGood.getSkuId(), pintuan.getStartTime(), pintuan.getEndTime(), pintuan.getId());
                //查询是否在同一时间段参与了限时抢购活动
                count += promotionGoodsService.findInnerOverlapPromotionGoods(PromotionTypeEnum.PINTUAN.name(), promotionGood.getSkuId(), pintuan.getStartTime(), pintuan.getEndTime(), pintuan.getId());
                if (count > 0) {
                    log.error("商品[" + promotionGood.getGoodsName() + "]已经在重叠的时间段参加了秒杀活动或拼团活动，不能参加拼团活动");
                    throw new ServiceException("商品[" + promotionGood.getGoodsName() + "]已经在重叠的时间段参加了秒杀活动或拼团活动，不能参加拼团活动");
                }
                promotionGood.setOriginalQuantity(promotionGood.getQuantity());
            }
            PromotionGoodsSearchParams searchParams = new PromotionGoodsSearchParams();
            searchParams.setPromotionId(pintuan.getId());
            searchParams.setPromotionType(PromotionTypeEnum.PINTUAN.name());
            promotionGoodsService.deletePromotionGoods(searchParams);
            promotionGoodsService.saveBatch(promotionGoods);
        }
    }

    @Override
    public List<PromotionGoods> getPintuanGoodsSkuList (String pintuanId, String goodsId) {
        List<PromotionGoods> reusltList = new ArrayList<>();
        List<PromotionGoods> promotionGoodsList = promotionGoodsService.list(new LambdaQueryWrapper<PromotionGoods>().eq(PromotionGoods::getPromotionId, pintuanId).eq(PromotionGoods::getGoodsId, goodsId));
        if (!promotionGoodsList.isEmpty()) {
            for (PromotionGoods promotionGoods : promotionGoodsList) {
                GoodsSku goodsSku = goodsClient.getCanPromotionGoodsSkuByIdFromCache(promotionGoods.getSkuId());
                if (goodsSku != null) {
                    if (goodsSku.getQuantity() == 0) {
                        continue;
                    }
                    promotionGoods.setThumbnail(goodsSku.getThumbnail());
                    promotionGoods.setGoodsId(goodsSku.getGoodsId());
                    promotionGoods.setGoodsName(goodsSku.getGoodsName());
                    promotionGoods.setSkuQuantity(goodsSku.getQuantity());
                    promotionGoods.setOriginalPrice(promotionGoods.getOriginalPrice());
                }
                reusltList.add(promotionGoods);
            }
        }else {
            GoodsSearchParams searchParams = new GoodsSearchParams();
            searchParams.setGoodsId(goodsId);
            List<GoodsSku> goodsSkuByList = goodsClient.getGoodsSkuByList(searchParams);
            if (!goodsSkuByList.isEmpty()) {
                for (GoodsSku goodsSku : goodsSkuByList) {
                    if (goodsSku.getQuantity() == 0) {
                        continue;
                    }
                    PromotionGoods promotionGoods = new PromotionGoods();
                    promotionGoods.setThumbnail(goodsSku.getThumbnail());
                    promotionGoods.setGoodsId(goodsSku.getGoodsId());
                    promotionGoods.setGoodsName(goodsSku.getGoodsName());
                    promotionGoods.setSkuQuantity(goodsSku.getQuantity());
                    promotionGoods.setOriginalPrice(goodsSku.getPrice());
                    promotionGoods.setSkuId(goodsSku.getId());
                    promotionGoods.setPrice(0D);
                    promotionGoods.setQuantity(0);
                    promotionGoods.setVirtualSalesNum(0);
                    reusltList.add(promotionGoods);
                }
            }
        }
        return reusltList;
    }

    @Override
    public void deletePinTuanGoods (String promotionId, String goodsId) {
        Pintuan pintuan = this.getById(promotionId);
        if (pintuan == null) {
            log.error("拼团活动id[" + promotionId + "]的拼团活动不存在！");
            throw new ServiceException(ResultCode.PINTUAN_NOT_EXIST_ERROR);
        }
        List<PromotionGoods> promotionGoodsList = promotionGoodsService.list(new LambdaQueryWrapper<PromotionGoods>().eq(PromotionGoods::getPromotionId, promotionId).eq(PromotionGoods::getGoodsId, goodsId));
        if (promotionGoodsList.isEmpty()) {
            throw new ServiceException("当前商品没有参与拼团活动");
        }

        promotionGoodsService.removeBatchByIds(promotionGoodsList.stream().map(PromotionGoods::getId).toList());

        List<String> skuIds = promotionGoodsList.stream().map(PromotionGoods::getSkuId).toList();
        Map<Object, Object> params = MapBuilder.create()
                .put("promotionKey", this.getPromotionType() + "-" + promotionId)
                .put("scopeId", ArrayUtil.join(skuIds.toArray(), ","))
                .build();

        applicationEventPublisher.publishEvent(TransactionCommitSendMQEvent.builder().source("删除商品促销事件").exchange(amqpExchangeProperties.getGoods()).routingKey(GoodsRoutingKey.DELETE_GOODS_INDEX_PROMOTIONS).message(params).build());
    }

}